/*--------------------------------------------------------------------------------------*\
**
** skeleton_transformer_window.cpp
**
** Heroes IV
** Copyright 2001, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "skeleton_transformer_window.h"

#include "adventure_map.h"
#include "army.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_group_ptr.h"
#include "bitmap_group_window.h"
#include "bitmap_layer_cache_window.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "button_group.h"
#include "combat_actor_action.h"
#include "combat_sounds.h"
#include "creature_array_window.h"
#include "creature_ability.h"
#include "creature_traits.h"
#include "creature_type.h"
#include "external_string.h"
#include "format_string.h"
#include "hero.h"
#include "music.h"
#include "sound.h"
#include "standard_fonts.h"
#include "toggle_button.h"
#include "town.h"

extern  t_button_cache const		k_close_button;
extern  t_bitmap_group_cache        g_creature_rings;
extern  t_button_cache              g_max_button;
t_button* create_blacksmith_button( std::string const& name, t_bitmap_group_ptr bitmap_ptr, t_window *parent_window );

namespace 
{ // unnamed namespace

    t_bitmap_group_cache        k_skeleton_transformer_bitmaps ("dialog.skeleton_transformer");
    t_external_string const     k_text_skeleton_transformer_title( "skeleton_transformer_title.misc" );
    t_external_string const     k_text_skeleton_transformer_text( "skeleton_transformer_text.misc" );
    t_external_string const     k_text_transform_denied( "skeleton_transformer_transform_denied.misc" );
    t_external_string const     k_text_transform_button( "skeleton_transformer_transform_button.misc" );
    t_external_string const     k_text_max_button( "skeleton_transformer_max_button.misc" );

    typedef std::vector<t_toggle_button*> t_toggle_button_list;

    class t_creature_select_array_window : public t_window
    {
    public:
	    enum t_layout
    	{
    		k_single_row,
    		k_top_row,
    		k_bottom_row,
    		k_stacked_rows
    	};

        t_creature_select_array_window( t_screen_rect const& origin, t_creature_array* army, t_layout layout,
                        t_skeleton_transformer_window* parent, t_transformer_window_list &window_list,
						int player_number );

    protected:
    	t_bitmap_group_ptr             m_bitmaps;
    };
}

/*
** Create new button from layer bitmaps.
*/
static void create_creature_button( t_button* button, t_screen_point& origin, std::string const& name,
                t_bitmap_group_ptr bitmap_ptr )
{
	t_window*			  holder;
	t_window*             window;
	t_bitmap_layer const* layer;
	t_screen_point        layer_point;
	t_screen_rect         rect;
	
    // Find released image.
	layer = bitmap_ptr->find( name );
	layer_point = layer->get_rect().top_left(); // + origin;
	
	rect = t_screen_rect(0,0,0,0);
	
	// create the "released" image
	holder = new t_window( rect, t_window::k_completely_transparent, button );
	window = new t_bitmap_layer_window( layer, -layer_point, holder );
	holder->set_size_from_children();
	button->set_released_image( holder );
    
	// create the "pressed" image
	layer = bitmap_ptr->find( name + "_highlight" );
	holder = new t_window( rect, t_window::k_completely_transparent, button );
	window = new t_bitmap_layer_window( layer, -layer_point, holder );
	holder->set_size_from_children();
	button->set_pressed_image( holder );

	// create the "disabled" image
	layer = bitmap_ptr->find( name + "_disabled" );
	holder = new t_window( rect, t_window::k_completely_transparent, button );
	window = new t_bitmap_layer_window( layer, -layer_point, holder );
	holder->set_size_from_children();
	button->set_disabled_image( holder );
}

/*
** Control for skeleton transformer which allows you to select one or more creatures.
*/
t_creature_select_array_window::t_creature_select_array_window( t_screen_rect const& origin_rect, t_creature_array* creatures, 
				t_layout layout, t_skeleton_transformer_window* parent, t_transformer_window_list &item_list,
				int player_number )
						: t_window( k_completely_transparent, parent )
{
	t_screen_point  point;
    int             i;
    int             row;
    int             column;
	t_screen_rect   rect;

	m_bitmaps = g_creature_rings.get();
	init( origin_rect );

	static char const* k_names[3][3] = 
	{
		{ "top_left",		"top",		"top_right" },
		{ "left",			"middle",	"right" },
		{ "bottom_left",	"bottom",	"bottom_right" }
	};

	static int const k_layout[4][t_creature_array::k_size][2] =
	{
		{{ 1, 0 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 2 }},
		{{ 0, 0 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 2 }},
		{{ 2, 0 }, { 2, 1 }, { 2, 1 }, { 2, 1 }, { 2, 1 }, { 2, 1 }, { 2, 2 }},
		{{ 0, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 }, { 0, 1 }, { 2, 2 }, { 1, 2 }}
	};

	std::string             layer_name;
	t_bitmap_layer const*   layer;
    t_screen_point          frame_point;
	t_bitmap_layer const*   inset = m_bitmaps->find( "inset" );
	t_screen_point          inset_offset = inset->get_rect().top_left();
	t_bitmap_layer const*   inset_text = m_bitmaps->find( "inset_text" );
	point.x = 0;
	point.y = 0;

    // Go through creature array.
    for (i = 0; i < t_creature_array::k_size; i++)
	{
		t_creature_stack const& creature = (*creatures)[i];
        t_transformer_window_item* item_ptr = new t_transformer_window_item;
        t_bitmap_layer_ptr creature_portrait = creature.get_portrait();

	    t_toggle_button * button_ptr;
	    button_ptr = new t_toggle_button( point, this, false );

		row = k_layout[layout][i][0];
		column = k_layout[layout][i][1];

		layer_name = k_names[row][column];
        
        // Create creature portrait.
	    t_window* holder = new t_window( t_screen_rect(0,0,0,0), t_window::k_completely_transparent, button_ptr );
	    layer = m_bitmaps->find( layer_name );
	    frame_point = layer->get_rect().top_left();

	    t_bitmap_layer_window * portrait_window;
	    rect = m_bitmaps->find( "portrait" )->get_rect();
        portrait_window = new t_bitmap_layer_window( t_bitmap_layer_ptr(),
	                                rect.top_left() - frame_point, holder );
        portrait_window->set_bitmap( creature_portrait );
        portrait_window->set_help_balloon_text( creature.get_name() );
	    holder->set_size_from_children();
        item_ptr->portrait = portrait_window;

        // Create creature button.
        create_creature_button( button_ptr, point, layer_name, m_bitmaps );

        item_ptr->button_ptr = button_ptr;

        // If creature exists, create inset for quantity text.
		if ( creature_portrait )
        {
		    item_ptr->inset = new t_bitmap_layer_window( inset, point - frame_point, this ); //button_ptr );
 		
	        t_screen_rect  text_rect = inset_text->get_rect() - inset_offset;
            item_ptr->text = new t_text_window( get_font( text_rect.height() ), text_rect, item_ptr->inset, "", t_pixel_24( 0,0,0 ) );
    		item_ptr->text->set_center_horizontal();
    		item_ptr->text->set_drop_shadow( true, t_pixel_24(200,200,200) );
    		item_ptr->text->set_text( format_string("%d", creature.get_number() ) );
        }

        // Disqualifying conditions for transforming:
        if (creature_portrait == 0)
            button_ptr->enable( false );

        if (creature.get_hero())
            button_ptr->enable( false );
	
        if (creature.has_ability( k_ability_mechanical ))
            button_ptr->enable( false );
        
        if (creature.has_ability( k_ability_undead ))
            button_ptr->enable( false );
        
        if (creature.has_ability( k_ability_elemental ))
            button_ptr->enable( false );

		if ( creatures->get_owner_number() != player_number )
			button_ptr->enable( false );
		
        // Get next offset - no stacked rows.
		point.x += layer->get_width();
        item_list.push_back( *item_ptr );
    }

	set_size_from_children();

}

/*---------------------------------------------------------------------------------------*\
**
** Skeleton transformer.
**
\*---------------------------------------------------------------------------------------*/
t_skeleton_transformer_window::t_skeleton_transformer_window( t_window* parent, t_town* town_ptr, t_army* adjacent_army )
                   : t_window( k_completely_transparent, parent )
{
	t_screen_rect rect;
	t_adventure_map & map = *town_ptr->get_map();
	//t_creature_array * garrison_creature_array = &town_ptr->get_garrison();
	
    m_background_bitmaps_ptr = k_skeleton_transformer_bitmaps.get();
    m_adjacent_creatures = adjacent_army;
    m_garrison_creatures = &town_ptr->get_garrison();
	
	/*
    ** Create background bitmap.
    */
	t_bitmap_layer const*   layer;
	t_window*               background;
	t_screen_point          origin(0,0);

	layer = m_background_bitmaps_ptr->find( "background" );
	background = new t_bitmap_layer_window( layer, origin, this );

    // Set position.
	t_screen_rect parent_rect;
    parent_rect = get_parent()->get_client_rect();
	rect = m_background_bitmaps_ptr->get_rect();
	rect += (parent_rect.size() - rect.size()) / 2;
	init( rect );

    t_creature_select_array_window* creature_window_ptr;
    t_bitmap_group_ptr ring_bitmaps = g_creature_rings.get();

    // Show adjacent army creatures.
	rect = m_background_bitmaps_ptr->find( "garrison_rings" )->get_rect();
	layer = ring_bitmaps->find( "top" );
	rect += t_screen_point(0,layer->get_height());
    creature_window_ptr = new t_creature_select_array_window( rect, m_adjacent_creatures, t_creature_select_array_window::k_bottom_row,
                    this, m_adjacent_window_list, map.get_player_number() );

    // Show garrison creatures.
	rect = m_background_bitmaps_ptr->find( "garrison_rings" )->get_rect();
    creature_window_ptr = new t_creature_select_array_window( rect, m_garrison_creatures, t_creature_select_array_window::k_top_row,
                    this, m_garrison_window_list, map.get_player_number() );
    
    // Create buttons.
    t_button*   button_ptr;

    // Create close button
	rect = m_background_bitmaps_ptr->find( "close_button" )->get_rect();
	button_ptr = new t_button( k_close_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_skeleton_transformer_window::close_click ));

    // Create max button
	rect = m_background_bitmaps_ptr->find( "max_button" )->get_rect();
	button_ptr = new t_button( g_max_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_skeleton_transformer_window::max_click ));
    button_ptr->set_help_balloon_text( k_text_max_button );

    // Transform button.
    m_transform_button_ptr = create_blacksmith_button( "transform_button", m_background_bitmaps_ptr, this );
	m_transform_button_ptr->set_click_handler( bound_handler( *this, &t_skeleton_transformer_window::transform_click ) );
    m_transform_button_ptr->set_help_balloon_text( k_text_transform_button );

    // Text.
    t_text_window*          text_window_ptr;
	
    rect = m_background_bitmaps_ptr->find( "title" )->get_rect();
	text_window_ptr  = new t_text_window( get_font( 18 ), rect, this, "", t_pixel_24(0,0,0) );
    text_window_ptr->set_text ( k_text_skeleton_transformer_title );
	text_window_ptr->set_center_horizontal();
    
    rect = m_background_bitmaps_ptr->find( "text" )->get_rect();
	text_window_ptr  = new t_text_window( get_font( 18 ), rect, this, "", t_pixel_24(0,0,0) );
    text_window_ptr->set_text ( k_text_skeleton_transformer_text );
	text_window_ptr->set_center_horizontal();
   
    int i;
    for (i = 0; i < t_creature_array::k_size; i++)
    {
        if (m_garrison_window_list[i].inset)
	        m_garrison_window_list[i].inset->move_to_front();
    }
}

/*
** Transform creature to undead.
**
** Level 1/2        -> skeletons
** Level 3          -> ghosts
** Level 4          -> vampires
**  except:
**    Dragons       -> bonedragons
**
*/
void t_skeleton_transformer_window::do_transform( t_creature_array *creature_array, int index, t_transformer_window_list &window_list )
{
	t_creature_stack*	stack = &(*creature_array)[ index ];
    int					num_creatures = stack->get_number();
    int					total_experience_val = stack->get_experience_value();
	t_creature_type		creature_type = stack->get_creature_type();
    int					level = ::get_traits( creature_type ).level;
            
    // Undead creature to change to.
	t_creature_type undead_creature_type;
    switch ( level )
    {
        case 1 :
        case 2 :
            undead_creature_type = k_skeleton;
            break;

        case 3 :
            undead_creature_type = k_ghost;
            break;

        case 4 :
            undead_creature_type = k_vampire;
            break;
    }
	if ((creature_type == k_faerie_dragon) || (creature_type == k_black_dragon))
    {
        undead_creature_type = k_bone_dragon;
    }

    int undead_experience_val = ::get_traits( undead_creature_type ).experience; //level;

	int	num_to_add = ( total_experience_val/undead_experience_val );
    
	if (num_to_add > num_creatures)
		num_to_add = num_creatures;
    if (num_to_add > 0)
    {
		t_sound_ptr sound = get_combat_sound( *stack, k_combat_actor_action_die );

		sound->play( get_sound_volume() );
        creature_array->clear( index );
        creature_array->add( undead_creature_type, num_to_add, index );
        window_list[ index ].portrait->set_bitmap( get_creature_portrait( undead_creature_type, 52 ) );
        window_list[ index ].button_ptr->set_help_balloon_text( get_creature_name( undead_creature_type, num_to_add, false ) );
        window_list[ index ].button_ptr->enable( false );
    	window_list[ index ].text->set_text( format_string("%d", num_to_add ) );
    }
    else
    {
        // Set error message.
        window_list[ index ].button_ptr->set_help_balloon_text( k_text_transform_denied );
    }
}

// Clicked transform button.
void t_skeleton_transformer_window::transform_click( t_button *button_ptr )
{
    int i;

    //for (i=0; i<m_garrison_buttons.size(); i++)
    for (i = 0; i < t_creature_array::k_size; i++)
    {
	    if ((m_garrison_window_list[i].button_ptr->is_enabled()) &&
                        (m_garrison_window_list[i].button_ptr->is_pressed()))
        {
            do_transform( m_garrison_creatures, i, m_garrison_window_list );
        }
    }
    for (i = 0; i < t_creature_array::k_size; i++)
    {
	    if ((m_adjacent_window_list[i].button_ptr->is_enabled()) &&
	                    (m_adjacent_window_list[i].button_ptr->is_pressed()))
        {
            do_transform( m_adjacent_creatures, i, m_adjacent_window_list );
        }
    }
}

// Select all eligible.
void t_skeleton_transformer_window::max_click( t_button *button_ptr )
{
    int i;
    for (i = 0; i < t_creature_array::k_size; i++)
    {
	    if (m_garrison_window_list[i].button_ptr->is_enabled())
	        m_garrison_window_list[i].button_ptr->set_pressed( true );
    }

    for (i = 0; i < t_creature_array::k_size; i++)
    {
	    if (m_adjacent_window_list[i].button_ptr->is_enabled())
	        m_adjacent_window_list[i].button_ptr->set_pressed( true );
    }
}

void t_skeleton_transformer_window::close_click( t_button *button_ptr )
{
    close();    
}

